package com.changer.common.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

import com.changer.common.service.CacheService;
import com.changer.framework.util.GoogleJsonUtils;

/**
 * 适合后端缓存Redis服务器为一台或多台的情形。
 * @author jiwei.guo
 */
public abstract class RedisCacheServiceImpl implements CacheService{

	private JedisPool jedisPool;
	
	private Jedis jedis;

	private ShardedJedisPool shardedJedisPool;

	private ShardedJedis shardedJedis;
	
	private Boolean singleServer;

	public Object get(String key) {
		String value = null;
		try {
			if(getSingleServer()){
				jedis = jedisPool.getResource();
				value = jedis.get(key);
			} else{
				shardedJedis = shardedJedisPool.getResource();
				value = shardedJedis.get(key);
			}
		} finally{
			if(jedis != null){
				jedis.close();
			}
			if(shardedJedis != null){
				shardedJedis.close();
			}
		}
		return value;
	}

	public void put(String key, Object value) {
		try {
			if(getSingleServer()){
				jedis = jedisPool.getResource();
				if(value instanceof String){
					jedis.set(key, (String)value);
				} else{
					jedis.set(key, GoogleJsonUtils.toJson(value));
				}
			} else{
				shardedJedis = shardedJedisPool.getResource();
				if(value instanceof String){
					shardedJedis.set(key, (String)value);
				} else{
					shardedJedis.set(key, GoogleJsonUtils.toJson(value));
				}
			}
			
		} finally{
			if(jedis != null){
				jedis.close();
			}
			if(shardedJedis != null){
				shardedJedis.close();
			}
		}
	}

	public void put(String key, Object value, Date expire) {
		try {
			if(getSingleServer()){
				jedis = jedisPool.getResource();
				if(value instanceof String){
					jedis.set(key, (String)value);
				} else{
					jedis.set(key, GoogleJsonUtils.toJson(value));
				}
				jedis.pexpireAt(key, expire.getTime());
			} else{
				shardedJedis = shardedJedisPool.getResource();
				if(value instanceof String){
					shardedJedis.set(key, (String)value);
				} else{
					shardedJedis.set(key, GoogleJsonUtils.toJson(value));
				}
				shardedJedis.pexpireAt(key, expire.getTime());
			}
		} finally{
			if(jedis != null){
				jedis.close();
			}
			if(shardedJedis != null){
				shardedJedis.close();
			}
		}
	}
	
	public boolean remove(String key) {
		try {
			if(getSingleServer()){
				jedis = jedisPool.getResource();
				jedis.del(key);
			} else{
				shardedJedis = shardedJedisPool.getResource();
				shardedJedis.del(key);
			}
		} finally{
			if(jedis != null){
				jedis.close();
			}
			if(shardedJedis != null){
				shardedJedis.close();
			}
		}
		return true;
	}

	public Boolean getSingleServer() {
		return singleServer;
	}

	public void setSingleServer(Boolean singleServer) {
		this.singleServer = singleServer;
	}

	public void incr(String key) {
		try {
			if(getSingleServer()){
				jedis = jedisPool.getResource();
				jedis.incr(key);
			} else{
				shardedJedis = shardedJedisPool.getResource();
				shardedJedis.incr(key);
			}
		} finally{
			if(jedis != null){
				jedis.close();
			}
			if(shardedJedis != null){
				shardedJedis.close();
			}
		}
	}

	public void rpush(String key, String value) {
		try {
			if(getSingleServer()){
				jedis = jedisPool.getResource();
				jedis.rpush(key, value);
			} else{
				shardedJedis = shardedJedisPool.getResource();
				shardedJedis.rpush(key, value);
			}
		} finally{
			if(jedis != null){
				jedis.close();
			}
			if(shardedJedis != null){
				shardedJedis.close();
			}
		}
	}

	public JedisPool getJedisPool() {
		return jedisPool;
	}

	public void setJedisPool(JedisPool jedisPool) {
		this.jedisPool = jedisPool;
	}

	public ShardedJedisPool getShardedJedisPool() {
		return shardedJedisPool;
	}

	public void setShardedJedisPool(ShardedJedisPool shardedJedisPool) {
		this.shardedJedisPool = shardedJedisPool;
	}

	public List<String> getRpush(String key) {
		try {
			if(getSingleServer()){
				jedis = jedisPool.getResource();
				return jedis.lrange(key, 0, -1);
			} else{
				shardedJedis = shardedJedisPool.getResource();
				return shardedJedis.lrange(key, 0, -1);
			}
		} finally{
			if(jedis != null){
				jedis.close();
			}
			if(shardedJedis != null){
				shardedJedis.close();
			}
		}
	}

	public boolean exists(String key) {
		try {
			if(getSingleServer()){
				jedis = jedisPool.getResource();
				return jedis.exists(key);
			} else{
				shardedJedis = shardedJedisPool.getResource();
				return shardedJedis.exists(key);
			}
		} finally{
			if(jedis != null){
				jedis.close();
			}
			if(shardedJedis != null){
				shardedJedis.close();
			}
		}
	}

	abstract public Set keys(String prefix);

	abstract public boolean removeKeys(Set keys);

}
